home *** CD-ROM | disk | FTP | other *** search
-
- /*
- * atexit.c
- *
- * Copyright (c) 1993 Symantec Corporation. All rights reserved.
- *
- */
-
- #include <MacHeaders>
-
- #include "stdlib.h"
- #include "stdio.h"
- #include "ansi_private.h"
-
-
- #define MAXEXIT 32
-
- /*
- * There are slots for MAXEXIT+2 shutdown routines:
- *
- * 0 reserved for stdio shutdown
- * 1 reserved for console shutdown
- * 2 .. MAXEXIT+1 available for user shutdown routines
- *
- * The routines will be called in descending slot order. Therefore,
- * the console shutdown routine (if any) and the stdio shutdown routine
- * (if any) are always called last.
- *
- * Shutdown routines installed with "atexit" (including the stdio and
- * console shutdown routines) are called only on normal termination, i.e.
- * calling "exit" or returning from "main".
- *
- * Shutdown routines installed with "_atexit" are called on "ExitToShell"
- * as well as on normal termination.
- *
- * When initiating any other form of termination (e.g. "Launch"), the
- * user can call "_exiting" to force shutdown routines to be called.
- *
- */
-
- int _abnormal_exit;
-
- static struct proc {
- __exit_func proc; /* non-zero -> shutdown routine */
- short always; /* false -> call only on normal exit */
- } exitproc[MAXEXIT + 2];
-
- static int next = 2;
- static __exit_func oldexit, oldES;
- static void *ptrES;
-
- static void normal_exit(void);
- static void newES(void);
- static void nop(void);
-
- #pragma parameter A0 get_vector
- static __exit_func get_vector(void) = { 0x206D, 0x006C }; /* "MOVEA.L 0x6C(A5),A0" */
-
- #pragma parameter set_vector(A0)
- static void set_vector(__exit_func) = { 0x2B48, 0x006C }; /* "MOVE.L A0,0x6C(A5)" */
-
- static void RememberA5(void);
- static long GetCurrentA5(void);
-
-
- /*
- * atexit - install user shutdown routine
- *
- */
-
- int
- atexit(__exit_func proc)
- {
- register struct proc *p;
-
- if (next > MAXEXIT + 1)
- return(-1);
-
- /* install proc in table */
-
- p = &exitproc[next++];
- p->proc = proc;
- /* p->always = 0; */
-
- /* install exit vector */
-
- RememberA5();
- if (!oldexit) {
- oldexit = get_vector();
- set_vector(normal_exit);
- }
- return(0);
- }
-
-
- /*
- * _atexit - install a critical shutdown routine
- *
- * Routines installed with "_atexit" are called even if the program does
- * not terminate normally, provided only that "ExitToShell" is called.
- *
- */
-
- int
- _atexit(__exit_func proc)
- {
- register struct proc *p;
- register struct { short jmp; __exit_func proc; } *q;
-
- if (next > MAXEXIT + 1)
- return(-1);
-
- /* install proc in table */
-
- p = &exitproc[next++];
- p->proc = proc;
- p->always = 1;
-
- /* install ExitToShell hook */
-
- RememberA5();
- if (!oldES) {
- oldES = (__exit_func) GetTrapAddress(0xA9F4);
- if (ROM85 >= 0)
- SetTrapAddress((long) newES, 0xA9F4);
- else {
- q = (void *) NewPtrSys(sizeof *q);
- q->jmp = 0x4EF9;
- q->proc = newES;
- SetTrapAddress((long) (ptrES = q), 0xA9F4);
- }
- }
- return(0);
- }
-
-
- /*
- * __atexit_console - install console shutdown routine
- *
- * This is called when a console window is opened.
- *
- */
-
- void
- __atexit_console(__exit_func proc)
- {
- int save = next;
-
- next = 1;
- atexit(proc);
- next = save;
- }
-
-
- /*
- * __atexit_stdio - install stdio shutdown routine
- *
- * This is called when stdio opens a file.
- *
- */
-
- void
- __atexit_stdio(__exit_func proc)
- {
- int save = next;
-
- next = 0;
- _atexit(proc);
- next = save;
- }
-
-
- /*
- * exit - normal program termination
- *
- * The exit status is ignored.
- *
- */
-
- void
- exit(int i)
- {
- (*get_vector())();
- ExitToShell();
- }
-
-
- /*
- * _exit - abnormal program termination
- *
- * The exit status is ignored.
- *
- */
-
- void
- _exit(int i)
- {
- ExitToShell();
- }
-
-
- /*
- * normal_exit - atexit vector
- *
- */
-
- static void
- normal_exit(void)
- {
- _exiting(1);
- }
-
-
- /*
- * newES - ExitToShell intercept
- *
- */
-
- static void
- newES(void)
- {
- _exiting(0);
- ExitToShell();
- }
-
-
- /*
- * _exiting - perform shutdown activity
- *
- * The argument controls which shutdown routines should be called:
- *
- * _exiting(1) call all installed shutdown routines
- * _exiting(0) call only routines installed with "_atexit"
- *
- */
-
- void
- _exiting(int normally)
- {
- register struct proc *p = &exitproc[MAXEXIT + 2];
- __exit_func proc;
- int i;
- long oldA5 = GetCurrentA5();
-
- if(oldA5)
- SetA5(GetCurrentA5());
-
- /* call installed routines */
-
- if (!normally)
- _abnormal_exit = 1;
- p = &exitproc[MAXEXIT + 2];
- for (i = MAXEXIT + 2; i--; ) {
- if (proc = (--p)->proc) {
- p->proc = 0;
- if (normally || p->always)
- (*proc)();
- }
- }
-
- /* deallocate ExitToShell intercept */
-
- if (ptrES) {
- DisposePtr(ptrES);
- ptrES = 0;
- }
-
- /* remove ExitToShell intercept */
-
- if (oldES) {
- SetTrapAddress((long) oldES, 0xA9F4);
- oldES = 0;
- }
-
- /* call original exit proc */
-
- if (oldexit)
- (*oldexit)();
- else
- (*get_vector())();
- oldexit = nop;
- if(oldA5)
- SetA5(oldA5);
- }
-
-
- /*
- * nop - do nothing
- *
- */
-
- static void
- nop(void)
- {
- }
-
-
- /*
- * __GetA5 - get pointer to PC-relative location in which to store our A5
- *
- */
-
- static void
- __GetA5(void)
- {
- asm {
- bsr.s @1
- dc.l 0 ; store A4 here
- @1 move.l (sp)+,a1
- }
- }
-
-
- /*
- * RememberA5 - remember our A5 in a PC-relative location
- *
- */
-
- static void
- RememberA5(void)
- {
- __GetA5(); asm { move.l a5,(a1) }
- }
-
-
- /*
- * GetCurrentA5 - obtain our A5 from its PC-relative location
- *
- */
-
- static long
- GetCurrentA5(void)
- {
- __GetA5(); asm { move.l (a1),d0 }
- }
-